package com.lgc.javathread.threadPoolTest;

import org.springframework.scheduling.concurrent.CustomizableThreadFactory;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 此种是alibaba开发手册建议的方式
 * Java开发手册中强制线程池不允许使用 Executors 去创建，而是通过 ThreadPoolExecutor 的方式，
 * 这样的处理方式让写的同学更加明确线程池的运行规则，规避资源耗尽的风险
 *
 * 说明：Executors 各个方法的弊端：
 * 1）newFixedThreadPool 和 newSingleThreadExecutor:
 * 主要问题是堆积的请求处理队列可能会耗费非常大的内存，甚至 OOM。
 * 2）newCachedThreadPool 和 newScheduledThreadPool:
 * 主要问题是线程数最大数是 Integer.MAX_VALUE，可能会创建数量非常多的线程，甚至 OOM。
 */
public class ThreadPoolProgram {
    public static void main(String[] args) {
        /*当提交一个新任务到线程池时首先线程池判断基本线程池(corePoolSize)是否已满？
        没满，创建一个工作线程来执行任务。满了，则进入下个流程；
        其次线程池判断工作队列(workQueue)是否已满？
        没满，则将新提交的任务存储在工作队列里。满了，则进入下个流程；
        最后线程池判断整个线程池(maximumPoolSize)是否已满？
        没满，则创建一个新的工作线程来执行任务，满了，则交给饱和策略来处理这个任务；
        如果线程池中的线程数量大于 corePoolSize 时，如果某线程空闲时间超过keepAliveTime，线程将被终止，
        直至线程池中的线程数目不大于corePoolSize；*/

        //https://www.fangzhipeng.com/javainterview/2019/03/22/threadpool.html
        // keepAliveTime：表示线程没有任务执行时最多保持多久时间会终止。
        // 默认情况下，只有当线程池中的线程数大于corePoolSize时，keepAliveTime才会起作用，
        // 直到线程池中的线程数不大于corePoolSize，即当线程池中的线程数大于corePoolSize时，如果一个线程空闲的时间达到keepAliveTime，则会终止，直到线程池中的线程数不超过corePoolSize。
        // 但是如果调用了allowCoreThreadTimeOut(boolean)方法，在线程池中的线程数不大于corePoolSize时，keepAliveTime参数也会起作用，直到线程池中的线程数为0；

        //workQueue：一个阻塞队列，用来存储等待执行的任务，这个参数的选择也很重要，会对线程池的运行过程产生重大影响，一般来说，这里的阻塞队列有以下几种选择：
        // new LinkedBlockingQueue<Runnable>()指的是没有设置固定大小的队列，
        // new ArrayBlockingQueue<>(3)有界
        // SynchronousQueue

//        threadFactory：线程工厂，主要用来创建线程；

//        handler：表示当拒绝处理任务时的策略，有以下四种取值：
//        ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
//        ThreadPoolExecutor.DiscardPolicy：也是丢弃任务，但是不抛出异常。
//        ThreadPoolExecutor.DiscardOldestPolicy：丢弃队列最前面的任务，然后重新尝试执行任务（重复此过程）
//        ThreadPoolExecutor.CallerRunsPolicy：由调用线程处理该任务

        //有界
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(90),
                new CustomizableThreadFactory("exec-outside-cache-"));
        //无界
//        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 1, TimeUnit.SECONDS, new LinkedBlockingDeque<>(),
//                new CustomizableThreadFactory("exec-outside-cache-"));

        try {
            for (int i = 0; i < 100; i++) {
                MyRunnable2 myRun = new MyRunnable2(i);
                executor.execute(myRun);
//                System.out.println("线程池中线程数目：" + executor.getPoolSize() + "，队列中等待执行的任务数目：" +
//                        executor.getQueue().size() + "，已执行玩别的任务数目：" + executor.getCompletedTaskCount());
            }

            try {
                Thread.sleep(3000);
            }catch (Exception e)
            {
                e.printStackTrace();
            }

            executor.shutdown();

            try {
                while (true)
                {
                    if(executor.isTerminated())
                    {
                        System.out.println("所有的子线程都结束了！");
                        break;
                    }
                    else {
                        System.out.println("执行中！");
                    }
                    Thread.sleep(1000);
                }
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
